package com.fxz.oauth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fxz.oauth.domain.Auth;
import com.fxz.oauth.domain.Role;
import com.fxz.oauth.domain.User;
import com.fxz.oauth.domain.UserRole;
import com.fxz.oauth.mapper.UserMapper;
import com.fxz.oauth.service.IRoleService;
import com.fxz.oauth.service.IUserRoleService;
import com.fxz.oauth.service.IUserService;
import com.fxz.oauth.util.Constants;
import com.fxz.oauth.util.JwtUtil;
import lombok.AllArgsConstructor;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Fxz
 * @version 1.0
 * @date 2021-08-04 10:26
 */

@AllArgsConstructor
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService, UserDetailsService {

    private final UserMapper userMapper;

    private final PasswordEncoder passwordEncoder;

    private final JwtUtil jwtUtil;

    private final IRoleService roleService;

    private final IUserRoleService userRoleService;

    /**
     * 登录、返回访问token和刷新token
     *
     * @param username
     * @param password
     * @return
     */
    @Override
    public Auth login(String username, String password) throws AuthenticationException {
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        if (ObjectUtils.isNotEmpty(user) && passwordEncoder.matches(password, user.getPassword())) {
            List<Long> roleIds = userRoleService.list(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, user.getId())).stream().map(item -> item.getRoleId()).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(roleIds)) {
                Collection<Role> roles = roleService.listByIds(roleIds);
                Set<Role> set = new HashSet<>();
                roles.forEach(item -> set.add(item));
                user.setAuthorities(set);
            }
            return new Auth(jwtUtil.createAccessToken(user), jwtUtil.createRefreshToken(user));
        } else {
            throw new BadCredentialsException("用户名或者密码错误!");
        }
    }

    @Transactional
    @Override
    public User register(User user) {
        //查询默认角色是否存在
        Role role = roleService.getOne(new LambdaQueryWrapper<Role>().eq(Role::getAuthority, Constants.ROLE_USER));
        //为用户密码进行编码
        user = user.withPassword(passwordEncoder.encode(user.getPassword()));
        this.save(user);
        //如果默认角色存在
        if (ObjectUtils.isNotEmpty(role)) {
            //设置用户角色 保存中间关系
            user = this.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, user.getUsername()));
            Set<Role> set = new TreeSet<>();
            set.add(role);
            user = user.withAuthorities(set);
            UserRole userRole = new UserRole();
            userRole.setUserId(user.getId());
            userRole.setRoleId(role.getId());
            userRoleService.save(userRole);
        }
        return user;
    }

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        return this.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, s));
    }
}
